package com.bayss.web.mock.aspect;

import com.alibaba.fastjson.JSON;
import com.bayss.web.mock.annotation.DataValue;
import com.bayss.web.mock.annotation.MockAble;
import com.bayss.web.mock.enums.MockDataType;
import com.bayss.web.mock.response.MockResp;
import com.bayss.web.mock.utils.AnnotationUtil;
import com.bayss.web.mock.utils.ValueUtil;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by px on 2016/11/1.
 */
@Component
@Aspect
public class MockAspect {
    public static final Logger logger = LoggerFactory.getLogger(MockAspect.class);

    @Pointcut("@annotation(com.bayss.web.mock.annotation.MockAble)")
    public void MockAble() {
    }

    @Around("MockAble() && @annotation(evict)")
    public Object aroundInit(ProceedingJoinPoint point, MockAble evict) throws Throwable {
        MethodSignature ms = (MethodSignature) point.getSignature();
        Method method = ms.getMethod();
        Object returnValue = handle(point, evict, method);
        return returnValue;
    }

    private Object handle(ProceedingJoinPoint point, MockAble evict, Method method) throws Throwable {
        logger.debug(".....................mock start!!!!!!!!!");
        Object returnValue;
        int length = evict.length();
        MockDataType type = evict.type();

        if (type == MockDataType.OBJECT) {
            returnValue = make(evict);
        } else if (type == MockDataType.LOOP) {
            returnValue = loopMake(evict.value(), null);
        } else {
            List<Object> value = new ArrayList<Object>(length);
            for (int i = 0; i < length; i++) {
                Object object = make(evict);
                value.add(object);
            }
            returnValue = value;
        }
        logger.debug(".....................mock end!!!!!!!!!!");
        return MockResp.success(returnValue);
    }


    /**
     * 根据注解内容获取假数据
     *
     * @param evict
     * @return
     */
    public static Object make(MockAble evict) {
        //得到注解名称
        Class modelClass = evict.value();
        Object value = null;
        try {
            value = modelClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


        Map<Field, Annotation[]> fieldAnnotationMap = AnnotationUtil.getClassAnnotationValues(modelClass);

        for (Map.Entry<Field, Annotation[]> entry : fieldAnnotationMap.entrySet()) {


            Field field = entry.getKey();
            Annotation[] annotations = entry.getValue();

            String dataValue = null;
            if (annotations != null && annotations.length > 0) {
                for (Annotation ann : annotations) {
                    if (ann instanceof DataValue) {
                        dataValue = ((DataValue) ann).value();
                    }
                }
            }

            if (StringUtils.isNotBlank(dataValue)) {
//                Pattern pattern = Pattern.compile("$\\{(.*)\\}");
//                Matcher matcher = pattern.matcher(dataValue);
//                if(matcher.find()){
//                    String key = matcher.group(1);
//                    dataValue = getValue(key);
//                }
                boolean flag = dataValue.indexOf("${") == 0;
                if (flag) {
                    String key = dataValue.replace("${", "").replace("}", "");
//                    dataValue = ValueUtil.getValue(key);
                }
            }

            Class<?> typeClass = field.getType();
            field.setAccessible(true);
            Object fieldValue = null;

            if (StringUtils.isNotBlank(dataValue) && !isBaseType(typeClass)) {

                if (typeClass == List.class) {
                    ParameterizedType pt = (ParameterizedType) field.getGenericType();
                    Class clz = (Class) pt.getActualTypeArguments()[0];

                    fieldValue = JSON.parseArray(dataValue, clz);
                } else {
                    fieldValue = JSON.parseObject(dataValue, typeClass);
                }
            } else {
                fieldValue = getFillValue(typeClass, dataValue);
//                Constructor con = null;
//                try {
//                    con = typeClass.getConstructor(typeClass);
//                    fieldValue = con.newInstance(dataValue);
//                    fieldValue = getFillValue(typeClass, dataValue);
//                } catch (NoSuchMethodException e) {
//                    e.printStackTrace();
//                }
            }

            try {
                field.set(value, fieldValue);

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        return value;
    }


    /**
     * 递归搞定所有实体bean
     *
     * @return
     */
    public static Object loopMake(Class<?> clazz, Annotation[] annotationses) {
        //判断是否是基本类型
        if (isBaseType(clazz)) {

            Annotation[] annotations = annotationses;

            String dataValue = "";
            for (Annotation ann : annotations) {
                if (ann instanceof DataValue) {
                    dataValue = ((DataValue) ann).value();
                }
            }

            Object fieldValue = getFillValue(clazz, dataValue);
            return fieldValue;

        } else {
            Object value = null;
            try {
                value = clazz.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }


            Map<Field, Annotation[]> fieldAnnotationMap = AnnotationUtil.getClassAnnotationValues(clazz);
            for (Map.Entry<Field, Annotation[]> entry : fieldAnnotationMap.entrySet()) {
                //得到字段
                Field field = entry.getKey();
                //得到注解
                Annotation[] annotations = entry.getValue();

                //得到值
                String dataValue = null;
                //类型
                MockDataType type = null;
                //长度
                int length = 0;

                if (annotations != null && annotations.length > 0) {
                    for (Annotation ann : annotations) {
                        if (ann instanceof DataValue) {
                            dataValue = ((DataValue) ann).value();
                            type = ((DataValue) ann).type();
                            length = ((DataValue) ann).length();
                        }
                    }
                }

                if (type == MockDataType.LIST) {
                    try {

                        List<Object> result = new ArrayList<Object>(length);
                        //泛型的类型
                        Class realField = getGenericTypeActualType(field);
                        if (realField == String.class && dataValue != null) {
                            String[] split = dataValue.split(",");
                            for (int i = 0; i < split.length; i++) {
                                result.add(split[i]);
                            }
                        } else {
                            for (int i = 0; i < length; i++) {
                                Object fieldValue = loopMake(realField, null);
                                result.add(fieldValue);
                            }
                        }

                        field.setAccessible(true);

                        field.set(value, result);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                } else if (type == MockDataType.OBJECT) {

                    Object fieldValue = loopMake(field.getType(), field.getAnnotations());
                    field.setAccessible(true);
                    try {
                        field.set(value, fieldValue);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }

            }
            return value;
        }

        //实例化目标对象

    }


    private static boolean isBaseType(Class<?> clazz) {
        if (clazz == short.class || clazz == Short.class
                || clazz == byte.class || clazz == Byte.class
                || clazz == int.class || clazz == Integer.class
                || clazz == long.class || clazz == Long.class
                || clazz == char.class || clazz == Character.class
                || clazz == float.class || clazz == Float.class
                || clazz == double.class || clazz == Double.class
                || clazz == boolean.class || clazz == Boolean.class
                || clazz == String.class) {//基本类型
            return true;
        }

        return false;
    }

    private static Object getFillValue(Class<?> clazz, String dataValue) {
        Object value = null;

        if (clazz == short.class || clazz == Short.class) {
            if (StringUtils.isBlank(dataValue)) {
                value = (short) 1;
            } else {
                value = new Short(dataValue);
            }
        } else if (clazz == byte.class || clazz == Byte.class) {
            if (StringUtils.isBlank(dataValue)) {
                value = (byte) 1;
            } else {
                value = new Byte(dataValue);
            }
        } else if (clazz == int.class || clazz == Integer.class) {
            if (StringUtils.isBlank(dataValue)) {
                value = ValueUtil.getIntValue();
            } else {
                value = new Integer(dataValue);
            }
        } else if (clazz == long.class || clazz == Long.class) {
            if (StringUtils.isBlank(dataValue)) {
                value = ValueUtil.getLongValue();
            } else {
                value = new Long(dataValue);
            }
        } else if (clazz == char.class || clazz == Character.class) {
            if (StringUtils.isBlank(dataValue)) {
                value = 'a';
            } else {
                value = dataValue.charAt(0);
            }
        } else if (clazz == float.class || clazz == Float.class) {
            if (StringUtils.isBlank(dataValue)) {
                value = ValueUtil.getFloatValue();
            } else {
                value = new Float(dataValue);
            }
        } else if (clazz == double.class || clazz == Double.class) {
            if (StringUtils.isBlank(dataValue)) {
                value = ValueUtil.getDoubleValue();
            } else {
                value = new Double(dataValue);
            }
        } else if (clazz == boolean.class || clazz == Boolean.class) {
            if (StringUtils.isBlank(dataValue)) {
                value = ValueUtil.getBooleanValue();
            } else {
                value = new Boolean(dataValue);
            }
        } else if (clazz == Date.class) {
            if (StringUtils.isBlank(dataValue)) {
                value = ValueUtil.getDateValue();
            } else {
                value = new Date(dataValue);
            }
        } else {
            return dataValue;
        }

        return value;
    }


    private static Class getGenericTypeActualType(Field clazz) {
        ParameterizedType pt = (ParameterizedType) clazz.getGenericType();
        return (Class) pt.getActualTypeArguments()[0];

    }
}
